#pragma once

#include <linux/types.h>

#define MEMBLOCK_ALLOC_ACCESSIBLE 0
#define MEMBLOCK_ALLOC_NOLEAKTRACE 1

/* We are using top down, so it is safe to use 0 here */
#define MEMBLOCK_LOW_LIMIT 0

enum memblock_flags
{
    MEMBLOCK_NONE = 0x0,           /* No special request */
    MEMBLOCK_HOTPLUG = 0x1,        /* hotpluggable region */
    MEMBLOCK_MIRROR = 0x2,         /* mirrored region */
    MEMBLOCK_NOMAP = 0x4,          /* don't add to kernel direct mapping */
    MEMBLOCK_DRIVER_MANAGED = 0x8, /* always detected via a driver */
    MEMBLOCK_RSRV_NOINIT = 0x10,   /* don't initialize struct pages */
};

struct memblock_region
{
    phys_addr_t base;
    phys_addr_t size;
    enum memblock_flags flags;
    int nid;
};

struct memblock_type
{
    unsigned long cnt;
    unsigned long max;
    phys_addr_t total_size;
    struct memblock_region *regions;
    char *name;
};

struct memblock
{
    bool bottom_up; /* is bottom up direction? */
    phys_addr_t current_limit;
    struct memblock_type memory;
    struct memblock_type reserved;
};

int memblock_add(phys_addr_t base, phys_addr_t size);

void *memblock_alloc(phys_addr_t size, phys_addr_t align);
int memblock_reserve(phys_addr_t base, phys_addr_t size);
phys_addr_t memblock_start_of_DRAM(void);

int memblock_get_region_node(const struct memblock_region *r);
phys_addr_t memblock_alloc_range_nid(phys_addr_t size,
                                     phys_addr_t align, phys_addr_t start,
                                     phys_addr_t end, int nid, bool exact_nid);
